package com.cm.biz;

import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * RPA 线程工厂
 *
 * @author LWang 2023.02.03
 * @since 1.0.0
 */
public class RpaThreadFactory implements ThreadFactory {
    private static final String DEFAULT_NAME = "Worker";
    private static final String MINUS_SIGN = "-";
    private static final int SLEEP_TIMES = 500;
    private final AtomicInteger nextId = new AtomicInteger(1);
    private final ThreadGroup threadGroup;

    private final String prefix;
    private final boolean daemon;

    /**
     * @param prefix 线程前缀
     * @param daemon 是否守护线程
     */
    RpaThreadFactory(String prefix, boolean daemon) {
        if (StringUtils.isBlank(prefix)) {
            prefix = DEFAULT_NAME;
        }
        if (prefix.endsWith(MINUS_SIGN)) {
            prefix = prefix.substring(0, prefix.length() - 1);
        }
        this.prefix = prefix;
        this.daemon = daemon;
        threadGroup = new ThreadGroup(prefix);
    }

    @Override
    public Thread newThread(@NotNull Runnable task) {
        String threadName = String.format("%s-%d", this.prefix, this.nextId.getAndIncrement());
        Thread thread = new Thread(this.threadGroup, task, threadName, 0);
        thread.setDaemon(this.daemon);
        return thread;
    }


    /**
     * 创建多个线程，并执行
     *
     * @param runnable 线程
     * @param amount   数量
     */
    public void runThreads(Runnable runnable, int amount) {
        runThreads(runnable, amount, true);
    }

    public void runThreads(Runnable runnable, int amount, boolean slowly) {
        if (runnable == null) {
            return;
        }
        if (amount <= 0) {
            amount = 1;
        }
        for (int i = 0; i < amount; i++) {
            this.newThread(runnable).start();
            // 缓步创建
            if (slowly) {
                try {
                    TimeUnit.MILLISECONDS.sleep(SLEEP_TIMES + ThreadLocalRandom.current().nextInt(SLEEP_TIMES));
                } catch (InterruptedException ie) {
                    // nothing to do
                }
            }
        }
    }
}